

#include "Photon.hpp"
#include "Math.hpp"
#include "Color.hpp"

#include <iostream>
#include <cmath>

using namespace com::toxiclabs::tsoc;
using namespace std;

PhotonMap::PhotonMap()
{
	pthread_mutex_init(&mutex_addphotons,NULL);	
}

PhotonMap::~PhotonMap()
{
}

void PhotonMap::AddPhotons(vector<Photon *> * photons)
{
	pthread_mutex_lock(&mutex_addphotons);
	for(int n=0;n<photons->size();n++)
	{
		this->photons.push_back(photons->at(n));
	}
	pthread_mutex_unlock(&mutex_addphotons);
	
	cout<<"* Catched: "<<this->photons.size()<<" photons"<<endl;
}

void PhotonMap::Clear()
{
	pthread_mutex_lock(&mutex_addphotons);
	for(int n=0;n<photons.size();n++)
	{
		delete photons[n];
	}
	
	photons.clear();
	
	for(int n=0;n<4096;n++)
	{
		hash[n].clear();
	}
	pthread_mutex_unlock(&mutex_addphotons);
}


void PhotonMap::Build()
{
	cout<<"* building photon grid..."<<endl;;
	
	/* AABB computing */
	bb_min.Set(10000.0f,10000.0f,10000.0f,0);
	bb_max.Set(-10000.0f,-10000.0f,-10000.0f,0);
	
	for(int n=0;n<photons.size();n++)
	{
		bb_min.x=(photons[n]->position.x<bb_min.x) ? photons[n]->position.x : bb_min.x;
		bb_min.y=(photons[n]->position.y<bb_min.y) ? photons[n]->position.y : bb_min.y;
		bb_min.z=(photons[n]->position.z<bb_min.z) ? photons[n]->position.z : bb_min.z;
		
		bb_max.x=(photons[n]->position.x>bb_max.x) ? photons[n]->position.x : bb_max.x;
		bb_max.y=(photons[n]->position.y>bb_max.y) ? photons[n]->position.y : bb_max.y;
		bb_max.z=(photons[n]->position.z>bb_max.z) ? photons[n]->position.z : bb_max.z;
	}
	
	bb_min.x-=0.1f;
	bb_min.y-=0.1f;
	bb_min.z-=0.1f;
	
	bb_max.x+=0.1f;
	bb_max.y+=0.1f;
	bb_max.z+=0.1f;
	
	/* grid size */
	cell_size_x=(bb_max.x-bb_min.x)/16.0f;
	cell_size_y=(bb_max.y-bb_min.y)/16.0f;
	cell_size_z=(bb_max.z-bb_min.z)/16.0f;
	/*
	cout<<"cell size x: "<<cell_size_x<<endl;
	cout<<"cell size y: "<<cell_size_y<<endl;
	cout<<"cell size z: "<<cell_size_z<<endl;
	*/
	/* inserting photons */
	for(int n=0;n<photons.size();n++)
	{
		int index;
		int gpx,gpy,gpz;
		
		
		gpx=(photons[n]->position.x-bb_min.x)/cell_size_x;
		gpy=(photons[n]->position.y-bb_min.y)/cell_size_y;
		gpz=(photons[n]->position.z-bb_min.z)/cell_size_z;
		
		index = gpx + gpy*16 + gpz*256; 
		
		hash[index].push_back(photons[n]);
		
	}
	cout<<" done"<<endl;
	/*
	cout<<"Analyzing hash..."<<endl;
	for(int n=0;n<1000;n++)
	{
		if(hash[n].size()>0)
		{
			cout<<"slot "<<n<<" size:"<<hash[n].size()<<endl;
		}
	}
	*/
}

int PhotonMap::Search(Vector &position,Vector &normal,int type,float radius,Color  *out_power)
{
	
	int xmin,xmax;
	int ymin,ymax;
	int zmin,zmax;
	float dist;
	int N=0;
	float dn;
	Photon * target;
	Color power;
	
	/* sets no power */
	power.Set(0,0,0,1);
	
	xmin=std::max(0,(int)((position.x-bb_min.x-radius)/cell_size_x));
	xmax=std::min(15,(int)((position.x-bb_min.x+radius)/cell_size_x));
	
	ymin=std::max(0,(int)((position.y-bb_min.y-radius)/cell_size_y));
	ymax=std::min(15,(int)((position.y-bb_min.y+radius)/cell_size_y));
	
	zmin=std::max(0,(int)((position.z-bb_min.z-radius)/cell_size_z));
	zmax=std::min(15,(int)((position.z-bb_min.z+radius)/cell_size_z));
	
	
	
	for(int i=xmin;i<=xmax;i++)
	{
		for(int j=ymin;j<=ymax;j++)
		{
			for(int k=zmin;k<=zmax;k++)
			{
				int index = i+(j<<4)+(k<<8);
				
				for(int n=0;n<hash[index].size();n++)
				{
					target=hash[index][n];
				
					if(target->type!=type)continue;
	
					
					Vector phi = position - target->position;
					dist=phi.Module();
				
					
					if(dist<radius)
					{
						
						
						
						dn=normal * target->normal;
												
						if(dn>0.7)
						{
							N++;
							
							//Color re = target->power * (1.0f-dist/radius);							
							//power=power+re;
							
							
							power = power + target->power;													
						}
						
					}
					
				}//for
			}//for
		}//for
	}
	
	

	out_power->Set(power.r,power.g,power.b,power.a);
	
	return N;
}

int PhotonMap::Size()
{
	return photons.size();
}

int PhotonMap::PrimarySize()
{
	int sz=0;
	
	for(int n=0;n<photons.size();n++)
	{
		if(photons[n]->type==TSOC_PHOTON_DIRECT)sz++;
	}
	
	return sz;
}
